<?php

abstract class BpfServiceModel extends BpfModel
{
  const METHOD_GET = 'GET';
  const METHOD_POST = 'POST';
  const METHOD_PUT = 'PUT';
  const METHOD_DELETE = 'DELETE';

  // 对接 node_beauty 服务框架
  protected $service = null;
  private $_serviceUrl = null;

  private function __init()
  {
    $serviceConfig = $this->getIni('service');
    if (!isset($serviceConfig['url'])) {
      throw new Azalea\E500Exception('Service config is invalid.');
    }
    if (!isset($this->service)) {
      // 未指定服务名, 通过传入类名获取
      $this->service = strtolower(substr(get_class($this), 0, -5));
    }
    $this->_serviceUrl = trim($serviceConfig['url'], '/') . '/' . $this->service;
  }

  public function request($method, $url, $params = [], $reqHeaders = [], $buildQuery = true)
  {
    $ch = curl_init();
    switch ($method) {
      case self::METHOD_GET:
        curl_setopt($ch, CURLOPT_HTTPGET, true);
        break;
      case self::METHOD_POST:
      case self::METHOD_PUT:
      case self::METHOD_DELETE:
        if ($method == self::METHOD_POST) {
          curl_setopt($ch, CURLOPT_POST, true);
        } else {
          curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        }
        if ($buildQuery) {
          curl_setopt($ch, CURLOPT_POSTFIELDS, preg_replace('/%5B[0-9]+%5D/simU', '', http_build_query($params)));
        } else {
          curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
        }
        break;
      default:
        curl_close($ch);
        return;
    }
    $serviceConfig = $this->getIni('service');
    $headers = array_merge([
      // 'accept-encoding: gzip',
      'request-time: ' . Azalea\TIME,
    ], $reqHeaders);
    $isService = true;
    if (strncasecmp($url, 'http://', 7) && strncasecmp($url, 'https://', 8)) {
      $url = $this->_serviceUrl . '/' . $url;
      $isService = false;
    }
    curl_setopt_array($ch, [
      CURLOPT_HTTPHEADER => $headers,
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_AUTOREFERER => true,
      CURLOPT_FOLLOWLOCATION => true,
      CURLOPT_TIMEOUT => $serviceConfig['timeout'] ?? 15,
      CURLOPT_CONNECTTIMEOUT => $serviceConfig['connecttimeout'] ?? 3,
      CURLOPT_URL => $url,
    ]);
    $response = curl_exec($ch);
    $httpInfo = curl_getinfo($ch);
    curl_close($ch);

    if ($response === false) {
      throw new Azalea\E500Exception('Service response is invalid.');
    } else {
      $httpCode = $httpInfo['http_code'];
      $httpContentType = $httpInfo['content_type'];
      if (-1 == $httpInfo['download_content_length']) {
        // $response = gzdecode($response);
      }
      if ($httpContentType == 'application/json') {
        $response = json_decode($response);
      }
      if ($httpCode >= 300) {
        $error = isset($response->message) ? $response->message : $response;
        if ($httpCode === 403) {
          throw new Azalea\E500Exception($error, 403);
        } else if ($httpCode === 500) {
          throw new Azalea\E500Exception($error,
              isset($response->code) ? $response->code : 500);
        } else {
          throw new Azalea\E500Exception($error);
        }
      }
      return !$isService && isset($response->result) ? $response->result : $response;
    }
  }

  protected function get($url, $params = [], $headers = [])
  {
    return $this->request(self::METHOD_GET, $url . ($params ? ('?' . http_build_query($params)) : ''), [], $headers);
  }

  protected function post($url, $params = [], $headers = [], $buildQuery = true)
  {
    return $this->request(self::METHOD_POST, $url, $params, $headers, $buildQuery);
  }

  protected function put($url, $params = [], $headers = [], $buildQuery = true)
  {
    return $this->request(self::METHOD_PUT, $url, $params, $headers, $buildQuery);
  }

  protected function del($url, $params = [], $headers = [], $buildQuery = true)
  {
    return $this->request(self::METHOD_DELETE, $url, $params, $headers, $buildQuery);
  }
}
